package edu.asu.cse360.model;

import java.io.Serializable;
import java.util.Calendar;
import java.util.Locale;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToOne;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import org.joda.time.DateTime;

@NamedQueries({
    @NamedQuery(name=ItemOrder.FIND_BY_STATUS_INCLUSIVE, query="select io from ItemOrder io where io.restaurant =:restaurant and io.status in(:statuses)"),
    @NamedQuery(name=ItemOrder.FIND_BY_DATE_RANGE, query="select io from ItemOrder io where io.restaurant =:restaurant and io.orderTime >= :startDate and io.orderTime <= :endDate"),
    @NamedQuery(name=ItemOrder.FIND_BY_SESSION, query="select io from ItemOrder io where io.customerSession = :customerSession"),
    @NamedQuery(name=ItemOrder.FIND_BY_MENU_ITEM, query="select io from ItemOrder io where io.menuItem = :menuItem"),
    @NamedQuery(name=ItemOrder.FIND_BY_WAIT_PERSON, query="select io from ItemOrder io where io.waitPerson = :waitPerson"),
    @NamedQuery(name=ItemOrder.FIND_BY_CHEF, query="select io from ItemOrder io where io.chef = :chef")

})
@Entity
@javax.persistence.Table(name="item_order")
public class ItemOrder implements Serializable, Idenfiable{
    public static final String FIND_BY_STATUS_INCLUSIVE = "ItemOrder.findByStatusInclusive";
    public static final String FIND_BY_DATE_RANGE = "ItemOrder.findByDateRange";
    public static final String FIND_BY_SESSION = "ItemOrder.findBySession";
    public static final String FIND_BY_MENU_ITEM = "ItemOrder.findByMenuItem";
    public static final String FIND_BY_WAIT_PERSON = "ItemOrder.findByWaitPerson";
    public static final String FIND_BY_CHEF = "ItemOrder.findByChef";

    @Id
    @Column(name="item_order_id")
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Integer id;

    @ManyToOne
    @JoinColumn(name="session_id")
    private CustomerSession customerSession;

    @Enumerated(EnumType.ORDINAL)
    private OrderStatus status;

    @Column(name="order_time")
    @Temporal(TemporalType.TIMESTAMP)
    private Calendar orderTime;

    @Column(name="deliver_time")
    @Temporal(TemporalType.TIMESTAMP)
    private Calendar deliverTime;

    @ManyToOne
    @JoinColumn(name="menu_item_id")
    private MenuItem menuItem;

    @ManyToOne
    @JoinColumn(name="wait_person_id")
    private WaitPerson waitPerson;

    @ManyToOne
    @JoinColumn(name="chef_id")
    private Chef chef;

    @OneToOne(cascade=CascadeType.ALL)
    @JoinColumn(name="order_cust_id")
    private OrderCustomization customization;

    @ManyToOne
    @JoinColumn(name="restaurant_id")
    private Restaurant restaurant;



    public ItemOrder(){
        this(null, null);
        // default constructor
    }

    public ItemOrder(MenuItem menuItem, Restaurant restaurant){
        this.menuItem = menuItem;
        this.status = OrderStatus.DEFAULT;
        this.customization = new OrderCustomization();
        this.restaurant = restaurant;
    }
    /**
     * @return the id
     */
    public Integer getId() {
        return id;
    }

    /**
     * @param id the id to set
     */
    public void setId(Integer id) {
        this.id = id;
    }

    /**
     * @return the table
     */
    public CustomerSession getCustomerSession() {
        return customerSession;
    }

    /**
     * @param table the table to set
     */
    public void setCustomerSession(CustomerSession customerSession) {
        this.customerSession = customerSession;
    }

    /**
     * @return the status
     */
    public OrderStatus getStatus() {
        return status;
    }

    /**
     * @param status the status to set
     */
    public void setStatus(OrderStatus status) {
        if(status == null){
            status = OrderStatus.DEFAULT;
        }
        this.status = status;
    }

    /**
     * @return the orderTime
     */
    public DateTime getOrderTime() {
        if(orderTime == null){
            return null;
        }else{
            return new DateTime(orderTime);
        }
    }

    /**
     * @param orderTime the orderTime to set
     */
    public void setOrderTime(DateTime orderTime) {
        if(orderTime == null){
            this.orderTime = null;
        }else{
            this.orderTime = orderTime.toCalendar(Locale.US);
        }
    }

    /**
     * @return the deliverTime
     */
    public DateTime getDeliverTime() {
        if(this.deliverTime == null){
            return null;
        }else{
            return new DateTime(this.deliverTime);
        }
    }

    /**
     * @param deliverTime the deliverTime to set
     */
    public void setDeliverTime(DateTime deliverTime) {
        if(deliverTime == null){
            this.deliverTime = null;
        }else{
            this.deliverTime = deliverTime.toCalendar(Locale.US);
        }
    }

    /**
     * @return the menuItem
     */
    public MenuItem getMenuItem() {
        return menuItem;
    }

    /**
     * @param menuItem the menuItem to set
     */
    public void setMenuItem(MenuItem menuItem) {
        this.menuItem = menuItem;
    }

    /**
     * @return the waitPerson
     */
    public WaitPerson getWaitPerson() {
        return waitPerson;
    }

    /**
     * @param waitPerson the waitPerson to set
     */
    public void setWaitPerson(WaitPerson waitPerson) {
        this.waitPerson = waitPerson;
    }

    /**
     * @return the chef
     */
    public Chef getChef() {
        return chef;
    }

    /**
     * @param chef the chef to set
     */
    public void setChef(Chef chef) {
        this.chef = chef;
    }

    /**
     * @return the customization
     */
    public OrderCustomization getCustomization() {
        return customization;
    }

    /**
     * @param customization the customization to set
     */
    public void setCustomization(OrderCustomization customization) {
        this.customization = customization;
    }

    @Override
    public int hashCode(){
        int hashCode = 17;
        hashCode = hashCode * 37 + ((customerSession == null) ? 0 : customerSession.hashCode());
        hashCode = hashCode * 37 + status.hashCode();
        hashCode = hashCode * 37 + ((orderTime == null) ? 0 : orderTime.hashCode());
        hashCode = hashCode * 37 + ((deliverTime == null) ? 0 : deliverTime.hashCode());
        hashCode = hashCode * 37 + ((menuItem == null) ? 0 : menuItem.hashCode());
        hashCode = hashCode * 37 + ((waitPerson == null)? 0 : waitPerson.hashCode());
        hashCode = hashCode * 37 + ((chef == null) ? 0 : chef.hashCode());
        hashCode = hashCode * 37 + ((customization == null) ? 0 : customization.hashCode());
        return hashCode;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (!(obj instanceof ItemOrder)) {
            return false;
        }
        ItemOrder other = (ItemOrder) obj;
        boolean equals = ( (customerSession == other.customerSession) || (customerSession != null && customerSession.equals(other.customerSession)) )
                      && ( status == other.status )
                      && ( (orderTime == other.orderTime) || (orderTime != null && orderTime.equals(other.orderTime)))
                      && ( (deliverTime ==  other.deliverTime) || (deliverTime != null && deliverTime.equals(other.deliverTime)))
                      && ( (menuItem == other.menuItem) || (menuItem != null && menuItem.equals(other.menuItem)))
                      && ( (waitPerson == other.waitPerson) || (waitPerson != null && waitPerson.equals(other.waitPerson)))
                      && ( (chef == other.chef ) || (chef != null && chef.equals(other.chef)))
                      && ( (customization == other.customization ) || (customization != null && customization.equals(other.customization)));
        return equals;
    }

    /**
     * @return the restaurant
     */
    public Restaurant getRestaurant() {
        return restaurant;
    }

    /**
     * @param restaurant the restaurant to set
     */
    public void setRestaurant(Restaurant restaurant) {
        this.restaurant = restaurant;
    }

}
